package widget.utils;

import android.content.Context;
import android.os.Environment;
import android.os.storage.StorageManager;
import android.text.TextUtils;

import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import library.logger.Logger;
import library.utils.Utils;

/**
 * Created by Fan on 2015/12/1.
 */
public class FileUtils {

    // to refer to bar.png under your package's asset/foo/ directory, use
    // "file:///android_asset/foo/bar.png".
    public static final String ASSET_BASE = "file:///android_asset/";
    // to refer to bar.png under your package's res/drawable/ directory, use
    // "file:///android_res/drawable/bar.png". Use "drawable" to refer to
    // "drawable-hdpi" directory as well.
    public static final String RESOURCE_BASE = "file:///android_res/";
    public static final String FILE_BASE = "file://";
    public static final String PROXY_BASE = "file:///cookieless_proxy/";
    public static final String CONTENT_BASE = "content:";


    private static Context context;
    private static final String Encoding_UTF8 = "UTF-8";

    public static void init(Context context) {
        FileUtils.context = context.getApplicationContext();
    }

    public static File getCacheDir() {
        return context.getCacheDir();
    }

    public static File getObbFile(String fileName) {
        return new File(context.getObbDir(), fileName);
    }

    public static File getCacheFile(String fileName) {
        return new File(getCacheDir().getAbsolutePath() + File.separator + fileName);
    }

    public static File getTempDir() {
        return context.getDir("temp", Context.MODE_PRIVATE);
    }

    public static File getTempFile(String fileName) {
        return new File(getTempDir().getAbsolutePath() + File.separator + fileName);
    }

    public static File getFilesDir() {
        return context.getFilesDir();
    }

    public static File getFilesFile(String fileName) {
        return new File(getFilesDir().getAbsolutePath() + File.separator + fileName);
    }

    public static File getExternalCacheDir() {
        return context.getExternalCacheDir();
    }

    public static File getExternalCacheFile(String fileName) {
        return new File(getExternalCacheDir().getAbsolutePath() + File.separator + fileName);
    }

    public static File getExternalDownloadDir() {
        return Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
    }

    public static File getExternalDownloadFile(String fileName) {
        return new File(getExternalDownloadDir().getAbsolutePath() + File.separator + fileName);
    }

    public static boolean deleteFile(final File file) {
        if (file != null && file.exists()) {
            if (file.isDirectory()) {
                final File[] Dirs = file.listFiles();
                for (final File dir : Dirs) {
                    if (dir.isDirectory()) {
                        deleteFile(dir);
                    } else {
                        dir.delete();
                    }
                }
            }
            file.delete();
            return true;
        }
        return false;
    }


    public static String getFileMD5(String file) {
        return getFileChecksum(new File(file), "MD5");
    }

    public static String getFileSHA(String file) {
        return getFileChecksum(new File(file), "SHA");
    }

    public static String getFileChecksum(File file, String method) {
        if (file == null || !file.isFile()) {
            return null;
        }
        MessageDigest digest = null;
        FileInputStream in = null;
        byte buffer[] = new byte[1024];
        int len;
        try {
            digest = MessageDigest.getInstance(method);
            in = new FileInputStream(file);
            while ((len = in.read(buffer, 0, 1024)) != -1) {
                digest.update(buffer, 0, len);
            }
        } catch (Exception e) {
            return null;
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (Exception e) {
                }
            }
        }
        BigInteger bigInt = new BigInteger(1, digest.digest());
        return bigInt.toString(16).toUpperCase();
    }


    public static String getInnerSDCardPath() {
        return Environment.getExternalStorageDirectory().getPath();
    }

    public static List<String> getVolumePaths(boolean containDefaultSDcard) {
        String inner = getInnerSDCardPath();
        List<String> list = new ArrayList<>();
        StorageManager sm = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
        try {
            String[] paths = (String[]) sm.getClass().getMethod("getVolumePaths").invoke(sm);
            for (int i = 0; i < paths.length; i++) {
                String path = paths[i];
                String status = (String) sm.getClass().getMethod("getVolumeState", String.class).invoke(sm, path);
                if (status.equals(Environment.MEDIA_MOUNTED)) {
                    File file = new File(path);
                    if (file.exists()) {
                        if (!containDefaultSDcard && file.getAbsolutePath().equals(inner) && file.canRead() && file.canWrite())
                            continue;
                        list.add(path);
                    }
                }
            }
        } catch (Exception e) {
            Logger.debug(e);
        }
        return list;
    }

    public static List<String> getExternalStoragePublicDirectorys() {
        List<String> list = new ArrayList<>();
        Map<String, Object> map = Utils.getFieldsValueMap(Environment.class, String.class);
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            String key = entry.getKey();
            Object value = entry.getValue();
            if (key != null && key.startsWith("DIRECTORY_")) {
                String dir = Environment.getExternalStoragePublicDirectory(String.valueOf(value)).getAbsolutePath();
                if (!TextUtils.isEmpty(dir))
                    list.add(dir);
            }
        }
        return list;
    }

    public static InputStream getInputStream(Object obj) {
        InputStream is = null;
        try {
            if (obj instanceof InputStream)
                is = (InputStream) obj;
            else if (obj instanceof String) {
                String path = (String) obj;
                if (!path.startsWith("/")) {
                    try {
                        is = context.getAssets().open(path);
                    } catch (Exception e) {

                    }
                }
                if (is == null) {
                    try {
                        is = new FileInputStream(path);
                    } catch (Exception e) {

                    }
                }
                if (is == null) {
                    is = new ByteArrayInputStream(path.getBytes());
                }
            } else if (obj instanceof Integer) {
                int id = (Integer) obj;
                is = context.getResources().openRawResource(id);
            }
        } catch (Exception e) {
            Logger.debug(e);
        }
        return is;
    }


    public static String readTxtFile(String file) throws Exception {
        return readTxtFile(file, Encoding_UTF8);
    }

    public static String readTxtFile(String file, String encoding) throws Exception {
        return readTxtFile(getInputStream(file), encoding);
    }


    public static String readTxtFile(InputStream is) throws Exception {
        return readTxtFile(is, Encoding_UTF8);
    }

    public static String readTxtFile(InputStream is, String encoding) throws IOException {
        try {
            int length = is.available();
            byte[] buffer = new byte[length];
            is.read(buffer);
            String res = new String(buffer, encoding);
            return res;
        } catch (IOException e) {
            throw e;
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                }
            }
        }
    }

    public static boolean write2File(String content, File target, boolean append) {
        if (TextUtils.isEmpty(content))
            return false;
        FileWriter filerWriter = null;//后面这个参数代表是不是要接上文件中原来的数据，不进行覆盖
        BufferedWriter bufWriter = null;
        try {
            if (!target.getParentFile().exists()) {
                target.getParentFile().mkdirs();
            }
            if (!target.exists())
                target.createNewFile();
            
            filerWriter = new FileWriter(target, append);
            bufWriter = new BufferedWriter(filerWriter);
            bufWriter.newLine();
            bufWriter.write(content);
            bufWriter.flush();
            return true;
        } catch (IOException e) {
            Logger.debug(e);
        } finally {
            if (filerWriter != null)
                try {
                    filerWriter.close();
                } catch (IOException e) {

                }
            if (bufWriter != null)
                try {
                    bufWriter.close();
                } catch (IOException e) {

                }
        }
        return false;
    }

    public static boolean saveText(File file, String s) {
        return write2File(s, file, false);
    }
}
